package org.grade.handler;

import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.grade.common.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.Locale;

/**
 * 提供了一个全局的异常处理机制，能够捕获异常并将其转换为具有标准格式的 HTTP 响应体，同时支持本地化消息显示
 */
@Slf4j
@ControllerAdvice
public class RestExceptionAdvice {
    //实现国际化消息支持
    @Autowired
    private MessageSource messageSource;

    public RestExceptionAdvice(MessageSource messageSource) {
        this.messageSource = messageSource;
    }


    /**
     * 处理 ServiceException 类型的异常
     * 首先，记录错误日志。
     * 然后，获取当前区域设置（Locale），用于从消息源中获取对应的本地化消息。
     * 使用 messageSource.getMessage 方法获取异常信息的本地化消息。如果获取到消息，就构造一个包含错误信息的响应体并返回，状态码设置为 INTERNAL_SERVER_ERROR（500）。如果获取不到消息，则直接使用异常信息构造响应体。
     * @param exception
     * @return
     */
    @ExceptionHandler({ServiceException.class})
    protected ResponseEntity<Object> onServiceException(Exception exception) {
        log.error("[ServiceException]", exception);
        Locale locale = LocaleContextHolder.getLocale();
        String message = this.messageSource.getMessage(exception.getMessage(), null, exception.getMessage(), locale);
        if (message != null) {
            return new ResponseEntity<>(ImmutableMap.of("success", false, "error", message), HttpStatus.INTERNAL_SERVER_ERROR);
        } else {
            return new ResponseEntity<>(ImmutableMap.of("success", false, "error", exception.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 处理其他类型的异常
     * 同样首先记录错误日志。
     * 获取当前区域设置。
     * 尝试从消息源中获取名为 "server.error" 的本地化消息。如果获取到消息，就构造一个包含该错误信息的响应体并返回；否则，直接使用异常的原始消息构造响应体。状态码也是 INTERNAL_SERVER_ERROR（500）。
     * @param exception
     * @return
     */
    @ExceptionHandler({Exception.class})
    protected ResponseEntity<Object> onException(Exception exception) {
        log.error("[Exception]", exception);
        Locale locale = LocaleContextHolder.getLocale();
        String error = this.messageSource.getMessage("server.error", null, "server.error", locale);
        if (error != null) {
            return new ResponseEntity<>(ImmutableMap.of("success", false, "error", error), HttpStatus.INTERNAL_SERVER_ERROR);
        } else {
            return new ResponseEntity<>(ImmutableMap.of("success", false, "error", exception.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}
